package org.biogroovy.io.ebi

import groovy.util.slurpersupport.GPathResult
import groovy.util.slurpersupport.NodeChild
import groovy.util.slurpersupport.NodeChildren
import groovyx.net.http.RESTClient

import org.biogroovy.io.AbsXmlSlurper
import org.biogroovy.io.IFetcher;
import org.biogroovy.models.Drug

/**
 * This class is used to fetch and parse compound-related data from the Chembl web service.
 * It makes use of the Groovy XmlSlurper to parse the XML.
 *
 */
class ChemblSlurper extends AbsXmlSlurper<Drug>{

	RESTClient client = new RESTClient('https://www.ebi.ac.uk/chemblws/')
	
	@Override
	public Drug fetch(String chemblId) {
		
		String path =  "compounds/${chemblId}"
		def resp = client.get(path: path)
		Drug drug = new Drug();
		
		if (resp.status == 200) {

			def data = resp.data
						
			parse(drug, data)
			
	
		} else {
			// something went wrong with the web service call
			println "ERROR: code=$resp.status"
		}
		return drug;
	}



	@Override
	public URL getUrl(String chemblId, Map<String, String> paramMap) {
		String urlStr = "https://www.ebi.ac.uk/chemblws/compounds/${chemblId}";
		return new URL(urlStr);
	}


	@Override
	public List<Drug> fetchAll(String id) throws IOException {
		List<Drug> drugList = new ArrayList<>();
		URL url = getUrl(id, null);
		XmlSlurper slurper = new XmlSlurper();
		GPathResult root = slurper.parse(url.openStream());
		
		root.compound.each{NodeChild node ->
			Drug drug = new Drug();
			parse(drug, node)
			drugList.add(drug)
		}
		return drugList;
	}


	@Override
	public Drug read(InputStream inputStream) throws IOException {
		XmlSlurper slurper = new XmlSlurper();
		GPathResult root = slurper.parse(inputStream)
		
		Drug drug = new Drug();
		parse(drug, root);
		return drug;
	}


	@Override
	public List<Drug> readList(InputStream inputStream) throws IOException {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public void parse(Drug drug, NodeChild cpd) {
		drug.name = cpd.preferredCompoundName.text();
		if(drug.name != null && drug.name != '') {
			drug.name = drug.name.split(' ').collect{ it.capitalize() }.join(' ')
		}
		drug.smiles = cpd.smiles
		drug.chemblId = cpd.chemblId
		drug.passesRuleOfThree = cpd.passesRuleOfThree.text().equalsIgnoreCase('YES')
		
		
		parseFloat(drug.molWeight, cpd.molecularWeight.text());
		drug.molFormula = cpd.molecularFormula
		parseFloat(drug.acdLogp, cpd.acdLogp.text())
		drug.isKnownDrug = cpd.knownDrug.text().equalsIgnoreCase('YES')
		
		drug.inChiKey = cpd.stdInChiKey
		parseFloat(drug.acdLogd, cpd.acdLogd.text())
		drug.isMedChemFriendly = cpd.medChemFriendly.text().equalsIgnoreCase('YES')
		parseInt(drug.rotatableBonds, cpd.rotatableBonds.text())
		parseFloat(drug.alogp, cpd.alogp.text())
		parseInt(drug.numRo5Violations, cpd.numRo5Violations.text());
		drug.synonyms = cpd.synonyms.text().trim()

	}
	
	/**
	 * This convenience method parses a floating point value from a string.
	 * If the string is empty or null, no change is made to the field value.
	 * @param field the field to be updated
	 * @param textValue the text value to be parsed
	 */
	private void parseFloat(Float field, String textValue) {
		if(textValue == null || textValue == '') {
			return;
		}
		field = Float.parseFloat(textValue)
	}
	
	/**
	 * This convenience method parses an integer value from a string.
	 * If the string is empty or null, no change is made to the field value.
	 * @param field the field to be updated
	 * @param textValue the text value to be parsed
	 */
	private void parseInt(Integer field, String textValue) {
		if(textValue == null || textValue == '') {
			return;
		}
		field = Integer.parseInt(textValue)
	}


	@Override
	protected void parseDbReferences(NodeChild root, Drug node) {
		// TODO Auto-generated method stub
		
	}



	@Override
	public IFetcher<Drug> getNewInstance() {
		return new ChemblSlurper();
	}




}
